package test;

import drds.tools.ShouldNeverHappenException;

import java.math.BigDecimal;
import java.math.BigInteger;


public class Decoder {


    public static Short decodeShortObject(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            int b = bytes[offset];
            if (b == Constants.NULL_BYTE_HIGH || b == Constants.NULL_BYTE_LOW) {
                return null;
            }
            return decodeShort(bytes, offset + 1);
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static short decodeShort(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            return (short) (((bytes[offset] << 8) | (bytes[offset + 1] & 0xff)) ^ 0x8000);
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }


    public static Integer decodeIntegerObject(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            int b = bytes[offset];
            if (b == Constants.NULL_BYTE_HIGH || b == Constants.NULL_BYTE_LOW) {
                return null;
            }
            return decodeInt(bytes, offset + 1);
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static int decodeInt(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            int value = (bytes[offset] << 24) | ((bytes[offset + 1] & 0xff) << 16) | ((bytes[offset + 2] & 0xff) << 8) | (bytes[offset + 3] & 0xff);
            return value ^ 0x80000000;
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static Long decodeLongObject(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            int b = bytes[offset];
            if (b == Constants.NULL_BYTE_HIGH || b == Constants.NULL_BYTE_LOW) {
                return null;
            }
            return decodeLong(bytes, offset + 1);
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static long decodeLong(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            return (((long) (((bytes[offset]) << 24) | ((bytes[offset + 1] & 0xff) << 16) | ((bytes[offset + 2] & 0xff) << 8) | ((bytes[offset + 3] & 0xff))) ^ 0x80000000) << 32) | (((((bytes[offset + 4]) << 24) | ((bytes[offset + 5] & 0xff) << 16) | ((bytes[offset + 6] & 0xff) << 8) | ((bytes[offset + 7] & 0xff))) & 0xffffffffL));
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static Float decodeFloatObject(byte[] bytes, int offset) throws CorruptEncodingException {
        int b = bytes[offset];
        if (b == Constants.NULL_BYTE_HIGH || b == Constants.NULL_BYTE_LOW) {
            return null;
        }
        int bits = decodeFloatBits(bytes, offset++);
        return Float.intBitsToFloat(bits);
    }

    protected static int decodeFloatBits(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            return (bytes[offset] << 24) | ((bytes[offset + 1] & 0xff) << 16) | ((bytes[offset + 2] & 0xff) << 8) | (bytes[offset + 3] & 0xff);
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static Double decodeDoubleObject(byte[] bytes, int offset) throws CorruptEncodingException {
        int b = bytes[offset];
        if (b == Constants.NULL_BYTE_HIGH || b == Constants.NULL_BYTE_LOW) {
            return null;
        }
        long bits = decodeDoubleBits(bytes, offset++);

        return Double.longBitsToDouble(bits);
    }

    protected static long decodeDoubleBits(byte[] bytes, int offset) throws CorruptEncodingException {
        try {
            return (((long) (((bytes[offset]) << 24) | ((bytes[offset + 1] & 0xff) << 16) | ((bytes[offset + 2] & 0xff) << 8) | ((bytes[offset + 3] & 0xff)))) << 32) | (((((bytes[offset + 4]) << 24) | ((bytes[offset + 5] & 0xff) << 16) | ((bytes[offset + 6] & 0xff) << 8) | ((bytes[offset + 7] & 0xff))) & 0xffffffffL));
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static int decodeBigDecimalObject(byte[] bytes, int offset, BigDecimal[] values) throws CorruptEncodingException {
        try {
            int b = bytes[offset++];
            int length = getLength(bytes, offset, b);
            offset += length;
            byte[] newBytes = new byte[length];
            System.arraycopy(bytes, offset, newBytes, 0, length);
            values[0] = new BigDecimal(new String(newBytes));
            return offset + length;

        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    private static int getLength(byte[] bytes, int offset, int b) {
        if (b == 1) {
            return bytes[offset++];
        } else if (b == 2) {

        } else if (b == 3) {

        } else if (b == 4) {

        } else if (b == 4) {

        } else if (b == 5) {

        } else {
            throw new ShouldNeverHappenException();
        }
        return 0;
    }

    public static int decodeBigIntegerObject(byte[] bytes, int offset, BigInteger[] values) throws CorruptEncodingException {
        try {
            int b = bytes[offset++];
            System.out.println(b + "---");
            int length = 0;
            if (b == 1) {
                length = bytes[offset++];
            }
            byte[] newBytes = new byte[length];
            System.arraycopy(bytes, offset, newBytes, 0, length);
            values[0] = new BigInteger(new String(newBytes));
            return offset + length;

        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

    public static int decodeStringObject(byte[] bytes, int offset, String[] values) throws CorruptEncodingException {
        try {
            int b = bytes[offset++];
            System.out.println(b + "---");
            int length = 0;
            if (b == 1) {
                length = bytes[offset++];
            }
            byte[] newBytes = new byte[length];
            System.arraycopy(bytes, offset, newBytes, 0, length);
            values[0] = new String(newBytes);
            return offset + length;
        } catch (IndexOutOfBoundsException e) {
            throw new CorruptEncodingException(null, e);
        }
    }

}
